#include "QRCodeManager.h"

QRCodeManager::QRCodeManager(QObject *parent) : QObject(parent)
{

}

QRCodeManager::~QRCodeManager()
{
    if(pMyCapManager != nullptr)
    {
        delete pMyCapManager;
        pMyCapManager = nullptr;
    }
    if(pQRDecoder != nullptr)
    {
        delete pQRDecoder;
        pQRDecoder = nullptr;
    }
}

void QRCodeManager::slot_QRCodeInit()
{
    pMyCapManager = new CameraManager();
    pMyCapManager->CameraInit();

    pQRDecoder = new QZXing();

    pQRDecoder->setDecoder( QZXing::DecoderFormat_QR_CODE | QZXing::DecoderFormat_EAN_13 );
    //optional settings
    //decoder.setSourceFilterType(QZXing::SourceFilter_ImageNormal | QZXing::SourceFilter_ImageInverted);
    pQRDecoder->setSourceFilterType(QZXing::SourceFilter_ImageNormal);
    pQRDecoder->setTryHarderBehaviour(QZXing::TryHarderBehaviour_ThoroughScanning | QZXing::TryHarderBehaviour_Rotate);
    mylog<<"qrcodeinit done!";
}

bool QRCodeManager::GetQRCodeFrame(Mat frame, QList<QRCode> &QRCodeFrame)
{

    //转换成灰度图
    Mat img_gray;
    cvtColor(frame,img_gray,COLOR_BGRA2GRAY);
    mylog<<"gray frame";
    //高斯模糊去除棱角和一些不必要的轮廓
    Mat img_guass;
    GaussianBlur(img_gray,img_guass,Size(3,3),0);
    mylog<<"guass frame";
    //利用大津法二值化
    Mat img_thres;
    threshold(img_gray,img_thres,0,255,THRESH_BINARY|THRESH_OTSU);
    mylog<<"thres frame";
    //定义开闭运算的核算子
    Mat kernel = getStructuringElement(MORPH_RECT,Size(2,2));
    //开运算
    Mat img_open;
    morphologyEx(img_thres,img_open,MORPH_OPEN,kernel);
    mylog<<"img_open frame";
    //闭运算
    Mat img_close;
    morphologyEx(img_open,img_close,MORPH_CLOSE,kernel);
    mylog<<"img_close frame";
    //查找轮廓
    vector<Vec4i> hierarchy;
    vector<vector<Point> > contours;
    findContours( img_close, contours,hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
    //查找出二维码上三个定位小方块
    QList<Rect> rct_positionHole;
    for(uint i=0;i<contours.size();i++)
    {
        if((hierarchy[i][0] != -1) && (hierarchy[i][1] != -1))
        {
            Rect ctr = boundingRect(contours[i]);
            float aspect_ratio = (float)ctr.width/ctr.height;
            //drawContours( frame, contours0, i, color,3);
            //限制长宽比
            if(aspect_ratio > 0.95 && aspect_ratio < 1.05)
            {
                int area = contourArea(contours[i]);
                //限制面积
                if(area > 750)
                {
                    //限制范围
                    if(ctr.width*ctr.height/(float)area <=1.2)
                    {
                        //drawContours( frame, contours0, i, color,3);
                        //rectangle(frame, ctr, cv::Scalar(111, 255, 0), 2);
                        rct_positionHole.push_back(ctr);
                        mylog<<hierarchy[i][1]<<" x:"<<ctr.x<<" y:"<<ctr.y<<" width:"<<ctr.width<<" height:"<<ctr.height<<" ratio:"<<aspect_ratio<<" fanwei:"<<ctr.width*ctr.height/(float)area;
        //                if(j==11)
        //                    break;
                   }
                }
            }
        }
    }
    //遍历上面找出的定位孔，查找出属于同一个二维码的三个孔，并按左上，左下，右上排列
    bool findpoint = false;
    for(int i=0;i<rct_positionHole.size()-2;i++)
    {
        findpoint = false;
        for(int j=i+1;j<rct_positionHole.size()-1;j++)
        {
            for(int k=j+1;k<rct_positionHole.size();k++)
            {
//                if(i == 1 && j == 3 && k == 7)
//                    mylog<<"11";
                QList<Rect> roi;
                roi.push_back(rct_positionHole[i]);
                roi.push_back(rct_positionHole[j]);
                roi.push_back(rct_positionHole[k]);
                //如果找到同一个二维码的三个孔
                if(detectQRcode(roi) == true)
                {
                    QRCode qrcode;
                    qrcode.LocatorHole = roi;
                    QRCodeFrame.push_back(qrcode);
                    mylog<<"find qr one";
                    findpoint = true;
                    break;
                }
            }
            if(findpoint == true)
            {
                break;
            }
        }
    }
    if(QRCodeFrame.empty())
    {
        QTime curtime = QTime::currentTime();
        QString aa = curtime.toString()+".png";
        cv::imwrite(aa.toStdString(), frame);
        return false;
    }
    else
        return true;
}

bool QRCodeManager::detectQRcode(QList<Rect> &po)
{
    bool findpoint = false;
    if(abs(po[0].x-po[1].x)<5 && abs(po[0].y-po[2].y)<5)
    {
        findpoint = true;
    }
    else if(abs(po[0].x-po[2].x)<5 && abs(po[0].y-po[1].y)<5)
    {
        po.swap(1,2);
        findpoint = true;
    }
    else if(abs(po[1].x-po[0].x)<5 && abs(po[1].y-po[2].y)<5)
    {
        po.swap(0,1);
        findpoint = true;

    }
    else if(abs(po[1].x-po[2].x)<5 && abs(po[1].y-po[0].y)<5)
    {
        po.swap(0,1);
        po.swap(1,2);
        findpoint = true;
    }
    else if(abs(po[2].x-po[0].x)<5 && abs(po[2].y-po[1].y)<5)
    {
        po.swap(0,2);
        po.swap(1,2);
        findpoint = true;
    }
    else if(abs(po[2].x-po[1].x)<5 && abs(po[2].y-po[0].y)<5)
    {
        po.swap(0,2);
        findpoint = true;
    }
    if(findpoint == true && po[1].y>po[0].y && po[2].x>po[0].x && abs((po[1].y - po[0].y) - (po[2].x - po[0].x))<10)
        return true;
    else
        return false;
}

void QRCodeManager::GetQRCodeText_Single(Mat frame, QRCode &QRCodeFrame)
{
    QRCodeFrame.GetQRCodeROI();
    Mat qrRoi(frame,QRCodeFrame.ROI);
    QRCodeFrame.text = DeCode_QZxing(qrRoi);
    mylog<<"get qr code:"<<QRCodeFrame.text;
}

void QRCodeManager::GetQRCodeText_Multi(Mat frame, QList<QRCode> &QRCodeFrame)
{
    for(int i=0;i<QRCodeFrame.size();i++)
    {
        GetQRCodeText_Single(frame,QRCodeFrame[i]);
    }
}

bool QRCodeManager::GetLocatorDistance(uint8_t type, uint8_t targetLocator, QList<QRCode> QRCodeFrame, int &realdistance, int center)
{
    bool isfind = false;
    for(int i=0;i<QRCodeFrame.size();i++)
    {
        if(targetLocator == QRCodeFrame[i].text.toInt())
        {
            if(type == ServoManager::QRLocateType_X)
            {
                //获取QR码X方向的像素宽度
                int pxQRWidth_x = QRCodeFrame[i].GetQRPxWidth();
                //获取QR码中心距离图像中心x方向的像素差
                int px2Center_x = QRCodeFrame[i].GetQR2CenterPxDistance_X(center);
                //计算x方向QR码中心距离图像中心的实际距离  单位mm
                realdistance = PxToMMConvert(pxQRWidth_x,px2Center_x);
                if(targetLocator == 1)
                {
                    QRCodeFrame[i].GetCenterPoint_Y();
                    QRLocateCommand::getInstance().layerOffset = QRCodeFrame[i].centerPoint.y;
                    mylog<<"set layerOffset :"<<QRLocateCommand::getInstance().layerOffset;
                }
                mylog<<"locator:"<<targetLocator<<" qrwidth:"<<pxQRWidth_x<<" px,centererror:"<<px2Center_x<<"px,realcentererror:"<<realdistance<<"mm";
            }
            else
            {
                //获取QR码X方向的像素宽度
                int pxQRWidth_y = QRCodeFrame[i].GetQRPxHeight();
                //获取QR码中心距离图像中心x方向的像素差
                int px2layeroffset_y = QRCodeFrame[i].GetQR2LayerOffsetDistance_Y(QRLocateCommand::getInstance().layerOffset);
                //计算x方向QR码中心距离图像中心的实际距离  单位mm
                realdistance = PxToMMConvert(pxQRWidth_y,px2layeroffset_y);
                mylog<<"locator:"<<targetLocator<<" qrheight:"<<pxQRWidth_y<<" px,centererror:"<<px2layeroffset_y<<"px,realerror:"<<realdistance<<"mm";
            }
            isfind = true;
        }
    }
    return isfind;
}

bool QRCodeManager::GetTargetArvQR(QList<QRCode> QRCodeFrame, QString text)
{
    for(int i=0;i<QRCodeFrame.size();i++)
    {
        if(QRCodeFrame[i].text == text)
        {
            return true;
        }
    }
    return false;
}

QString QRCodeManager::DeCode_QZxing(Mat qrcode)
{
    QImage QrCode = MatToImage(qrcode);
    QString result = pQRDecoder->decodeImage(QrCode);
    return result;
}

QImage QRCodeManager::MatToImage(Mat &mat)
{
    // 8-bits unsigned, NO. OF CHANNELS = 1
    if(mat.type() == CV_8UC1)
    {
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)
        image.setColorCount(256);
        for(int i = 0; i < 256; i++)
        {
            image.setColor(i, qRgb(i, i, i));
        }
        // Copy input Mat
        uchar *pSrc = mat.data;
        for(int row = 0; row < mat.rows; row ++)
        {
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3
    else if(mat.type() == CV_8UC3)
    {
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if(mat.type() == CV_8UC4)
    {
        //qDebug() << "CV_8UC4";
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
        //qDebug() << "ERROR: Mat could not be converted to QImage.";
        return QImage();
    }
}

int QRCodeManager::PxToMMConvert(float pxQRWidth, int pxQR2Center)
{
    float ratio = QRCodeManager::RealLocatorQRcode_mm/pxQRWidth;
    int realdistance = ratio * pxQR2Center;
    return realdistance;
}

void QRCodeManager::slot_StartQRLocateScan(quint8 type, quint8 locatorNo)
{
    mylog<<"qrmanager start qr sacn";
    Mat frame;
    int distanace=0;
    if(pMyCapManager->GetCurrentFrame(frame))
    {
        mylog<<"get a current frame";
        QList<QRCode> QRCodeframe;
        if(GetQRCodeFrame(frame,QRCodeframe))
        {
            mylog<<"get a qrcode frame";
            GetQRCodeText_Multi(frame,QRCodeframe);
            if(GetLocatorDistance(type,locatorNo,QRCodeframe,distanace,frame.cols/2))
            {
                emit sig_FindLocatorDistance(true,0);
                //mylog<<"distance:"<<distanace<<"mm";
            }
            else
            {
                emit sig_FindLocatorDistance(false,distanace);
                mylog<<"Can not find the index Locator in the frame!";
            }
        }
        else
        {
            emit sig_FindLocatorDistance(true,0);
            mylog<<"Can not find a QRCode in the frame!";
        }
    }
    else
    {
        emit sig_FindLocatorDistance(false,distanace);
        mylog<<"Can not get a frame from camera!";
    }
}

void QRCodeManager::slot_StartTargetArvQRScan()
{
    mylog<<"qrmanager start qr sacn";
    Mat frame;
    if(pMyCapManager->GetCurrentFrame(frame))
    {
        mylog<<"get a current frame";
        Rect rect(425,100,430,430);
        frame = frame(rect);
        QList<QRCode> QRCodeframe;
        if(GetQRCodeFrame(frame,QRCodeframe))
        {
            mylog<<"get a qrcode frame";
            GetQRCodeText_Multi(frame,QRCodeframe);
            //如果是目标档案的qr码
            if(GetTargetArvQR(QRCodeframe,InOutCabCommand::getInstance().QRCode))
            {
                emit sig_FindTargetArvQR(true,0);
                mylog<<"find the target QRCode in the frame!";
            }
            else
            {
                emit sig_FindTargetArvQR(false,0);
                mylog<<"Can not find the target QRCode in the frame!";
            }
        }
        else
        {
            emit sig_FindTargetArvQR(false,0);
            mylog<<"Can not find a QRCode in the frame!";
        }
    }
    else
    {
        emit sig_FindTargetArvQR(false,0);
        mylog<<"Can not get a frame from camera!";
    }
}
